package com.night.icm.service.base.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.SimpleDataDTO;
import com.night.icm.model.base.TeacherDTO;
import com.night.icm.model.core.UserDTO;
import com.night.icm.persistence.base.entity.Academy;
import com.night.icm.persistence.base.entity.Teacher;
import com.night.icm.persistence.base.repository.AcademyRepository;
import com.night.icm.persistence.base.repository.TeacherRepository;
import com.night.icm.persistence.core.entity.User;
import com.night.icm.service.base.mapper.TeacherMapper;
import com.night.icm.service.core.mapper.UserMapper;
import com.night.icm.service.core.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * TeacherServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/2/13
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class TeacherServiceImpl implements TeacherService {

    private final TeacherRepository teacherRepository;
    private final TeacherMapper teacherMapper;
    private final AcademyRepository academyRepository;
    private final UserMapper userMapper;
    private final UserService userService;

    @Autowired
    public TeacherServiceImpl(TeacherRepository teacherRepository, TeacherMapper teacherMapper, AcademyRepository academyRepository, UserMapper userMapper, UserService userService) {
        this.teacherRepository = teacherRepository;
        this.teacherMapper = teacherMapper;
        this.academyRepository = academyRepository;
        this.userMapper = userMapper;
        this.userService = userService;
    }

    /**
     * 分页查询教师信息
     *
     * @param page      页号，从0开始
     * @param size      每页记录条数
     * @param sort      排序字段，例如：字段1,asc,字段2,desc
     * @param academyId 所属学院
     * @param code      学生学号
     * @param name      学生姓名
     * @return 教师信息
     */
    @Override
    public PageDataDTO<TeacherDTO> findOnePage(int page, int size, String sort, String academyId, String code, String name) {
        PredicateBuilder<Teacher> pb = Specifications.<Teacher>and()
                .eq(StringUtils.isNotBlank(academyId), "academy.id", academyId)
                .like(StringUtils.isNotBlank(code), "code", "%" + code + "%")
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%");
        Page<Teacher> page1 = this.teacherRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<TeacherDTO> dtos = this.teacherMapper.toList(page1.getContent());
        return PageDataUtil.toPageData(page1, dtos);
    }

    /**
     * 添加教师
     *
     * @param teacherDTO 教师信息
     * @return 添加教师
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TeacherDTO create(TeacherDTO teacherDTO) {
        Teacher teacher = this.teacherMapper.toEntity(teacherDTO);
        // 关联所属学院
        Academy academy = this.getAcademyById(teacherDTO.getAcademyId());
        teacher.setAcademy(academy);
        this.teacherRepository.save(teacher);
        // 新建教师用户
        User user = this.createUser(teacherDTO);
        teacher.setUser(user);
        this.teacherRepository.save(teacher);
        return this.teacherMapper.toDTO(teacher);
    }

    /**
     * 根据id获取学院
     *
     * @param id 学院id
     * @return 学院
     */
    private Academy getAcademyById(String id) {
        Optional<Academy> optionalAcademy = this.academyRepository.findById(Long.valueOf(id));
        if (!optionalAcademy.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalAcademy.get();
    }

    /**
     * 新增教师时创建教师用户
     *
     * @param teacherDTO 教师编号号
     */
    private User createUser(TeacherDTO teacherDTO) {
        UserDTO userDTO = new UserDTO();
        // 教师编号作为登录用户名
        userDTO.setUsername(teacherDTO.getCode());
        // 登录密码默认6个9
        userDTO.setPassword("999999");
        // 设置教师身份权限，特殊身份有教务员、辅导员，都有教师权限
        if (teacherDTO.getIsSenator()) {
            // 教务员
            userDTO.setRole("ROLE_SENATOR");
        } else if (teacherDTO.getIsInstructor()) {
            // 辅导员
            userDTO.setRole("ROLE_INSTRUCTOR");
        } else {
            // 教师
            userDTO.setRole("ROLE_TEACHER");
        }
        UserDTO dto = this.userService.createUser(userDTO);
        return this.userMapper.toEntity(dto);
    }

    /**
     * 删除教师
     *
     * @param id 教师id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        Teacher teacher = this.getOne(id);
        String userId = teacher.getUser().getId().toString();
        this.teacherRepository.deleteById(Long.valueOf(id));
        // 同时删除教师登录信息
//        this.userService.deleteById(userId);
    }

    /**
     * 更新教师信息
     *
     * @param id         教师id
     * @param teacherDTO 教师信息
     * @return 教师信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TeacherDTO update(String id, TeacherDTO teacherDTO) {
        Teacher teacher = this.getOne(id);
        Long academyId = teacher.getAcademy().getId();
        this.teacherMapper.updateEntity(teacherDTO, teacher);
        if (!academyId.equals(Long.valueOf(teacherDTO.getAcademyId()))) {
            // 如果所属学院有变化，则修改所属学院
            Academy academy = this.getAcademyById(teacherDTO.getAcademyId());
            teacher.setAcademy(academy);
        }
        this.teacherRepository.save(teacher);
        // 判断身份
        UserDTO userDTO = this.userService.findByName(teacher.getCode());
        // 设置教师身份权限，特殊身份有教务员、辅导员，都有教师权限
        if (teacherDTO.getIsSenator()) {
            // 教务员
            userDTO.setRole("ROLE_SENATOR");
        } else if (teacherDTO.getIsInstructor()) {
            // 辅导员
            userDTO.setRole("ROLE_INSTRUCTOR");
        } else {
            // 教师
            userDTO.setRole("ROLE_TEACHER");
        }
        this.userService.update(userDTO.getId(), userDTO);
        return this.teacherMapper.toDTO(teacher);
    }

    /**
     * 通过id查找教师
     *
     * @param id 教师id
     * @return 教师信息
     */
    @Override
    public TeacherDTO findById(String id) {
        Teacher teacher = this.getOne(id);
        return this.teacherMapper.toDTO(teacher);
    }

    private Teacher getOne(String id) {
        Optional<Teacher> optionalTeacher = this.teacherRepository.findById(Long.valueOf(id));
        if (!optionalTeacher.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalTeacher.get();
    }

    /**
     * 查找所有教师，可选择排序
     *
     * @param param   排序参数
     * @param pattern 排序模式: asc/desc
     * @return 教师信息
     */
    @Override
    public List<TeacherDTO> findAll(String param, String pattern) {
        String keyType = "asc";
        Sort sort;
        if (keyType.equals(pattern)) {
            sort = new Sort(Sort.Direction.ASC, param);
        } else {
            sort = new Sort(Sort.Direction.DESC, param);
        }
        List<Teacher> all = this.teacherRepository.findAll(sort);
        return this.teacherMapper.toList(all);
    }

    /**
     * 检查教师是否已存在
     *
     * @param code 教师code
     * @return 教师信息
     */
    @Override
    public SimpleDataDTO<Boolean> checkCodeExist(String code) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        Teacher teacher = this.teacherRepository.findByCode(code);
        simpleDataDTO.setData(teacher != null);
        return simpleDataDTO;
    }

    /**
     * 通过用户id查找教师
     *
     * @param userId 用户id
     * @return 教师
     */
    @Override
    public TeacherDTO findByUserId(String userId) {
        Teacher teacher = this.teacherRepository.findByUserId(Integer.valueOf(userId));
        return this.teacherMapper.toDTO(teacher);
    }
}